#! /usr/bin/env python
# encoding: utf-8

"""The Request class makes avaiable the incoming request data in a more
accessible and more useful way, resolving the percenting encode.
"""

import urllib.parse as urllib

class Request:
    """Its properties contain request fields, from the "environ".
    Those are the informations sent from the client to the server.
    """

    def __init__(self, environ):
        """Analyzes the environ to fill the properties on which work.
        """

        self._form = dict()  # POST data
        self._querystring = dict()  # GET data
        self._cookies = dict()  # cookie container
        self._server = dict()  # server and other variables that didn't
                               # fit elsewhere
        self.method = str()  # 'GET' or 'POST' (always uppercase)

        self.method = environ.pop('REQUEST_METHOD').upper()

        if 'QUERY_STRING' in environ:
            self._querystring = self._data_to_dict(environ.pop('QUERY_STRING'))
        if 'HTTP_COOKIE' in environ:
            self._cookies = self._cookies_to_dict(environ.pop('HTTP_COOKIE'))

        self._server = environ

        try:
            post_length = int(environ.get('CONTENT_LENGTH', '0'))
        except ValueError:
            post_length = 0

        if post_length > 0:
            # this is needed because some wsgi server (such as wsgiref)
            # send a bytes instance, while other send a string instance.
            post_data = environ['wsgi.input'].read(post_length)
            try:
                post_data = post_data.decode()
            except AttributeError:
                pass

            self._form = self._data_to_dict(post_data)


    def _data_to_dict(self, data):
        """GET/POST data strings to dict
        """

        values = dict()

        data = urllib.unquote_plus(data)

        for element in [it.split('=') for it in data.split('&')]:
            if len(element) == 1:
                values[element[0]] = ""
            else:
                values[element[0]] = element[1]

        return values

    def _cookies_to_dict(self, data):
        """Parses the cookie sent back from the client and returns a dict.
        NOTE: given the string 'a' as the cookie string.
              'a' will be taken as identifier and there will be no value
              (= '' -void string-).
        """

        values = dict()

        data = urllib.unquote_plus(data)

        for element in data.split(';'):
            if '=' in element:
                lmost = element.find('=')
                k = element[:lmost].strip()
                v = element[lmost+1:].strip()
                values[k] = v
            else:
                values[element] = ""

        return values

    #
    ## public methods to gain access to Request attribute
    #

    def form(self, key=None, default=str()):
        """To gain access to POST resources.
        If key is None (by default) the whole dict will be returned.
        """

        if key is not None:
            return self._form.get(key, default)
        else:
            return self._form

    def querystring(self, key=None, default=str()):
        """To gain access to GET resources.
        If key is None (by default) the whole dict will be returned.
        """

        if key is not None:
            return self._querystring.get(key, default)
        else:
            return self._querystring

    def cookie(self, key=None, default=str()):
        """To obtain access to the Cookie data.
        If key is None (by default) the whole dict will be returned.
        """

        if key is not None:
            return self._cookies.get(key, default)
        else:
            return self._cookies

    def server(self, key=None, default=str()):
        """To obtain access to all other variables from the environ(nment).
        If key is None (by default) the whole dict will be returned.
        """

        if key is not None:
            return self._server.get(key, default)
        else:
            return self._server
